﻿Imports System.Reflection

<ComClass(ClsLine2d.ClassId, ClsLine2d.InterfaceId, ClsLine2d.EventsId)>
Public Class ClsLine2d

#Region "COM GUID"
    ' 这些 GUID 提供此类的 COM 标识 
    ' 及其 COM 接口。若更改它们，则现有的
    ' 客户端将不再能访问此类。
    Public Const ClassId As String = "5307724f-7cf0-4b0b-af8e-dacbdad7c017"
    Public Const InterfaceId As String = "0cb3e7de-f019-4725-a65d-b937936744d9"
    Public Const EventsId As String = "25c945b6-64c2-4a22-8fbf-3d78f9bbc7d9"
#End Region

    ' 可创建的 COM 类必须具有一个不带参数的 Public Sub New() 
    ' 否则， 将不会在 
    ' COM 注册表中注册此类，且无法通过
    ' CreateObject 创建此类。
    Public Sub New()
        MyBase.New()
    End Sub

#Region "字段和属性"

    Private _sp As ClsPoint2d
    Public Property StartPoint() As ClsPoint2d
        Get
            Return _sp
        End Get
        Set(ByVal value As ClsPoint2d)
            _sp = value
        End Set
    End Property
    Private _ep As ClsPoint2d

    Public Property EndPoint() As ClsPoint2d
        Get
            Return _ep
        End Get
        Set(ByVal value As ClsPoint2d)
            _ep = value
        End Set
    End Property

    Public ReadOnly Property Delta As ClsVector2d
        Get
            Return Me.StartPoint.GetVector2dTo(Me.EndPoint)
        End Get
    End Property

    Public ReadOnly Property UnitVector As ClsVector2d
        Get
            Return Me.Delta.UnitVector
        End Get
    End Property


    Public ReadOnly Property Length As Double
        Get
            Return Me.Delta.Length
        End Get
    End Property

    Public ReadOnly Property CoefficientA As Double
        Get
            Return Me.StartPoint.Y - Me.EndPoint.Y

        End Get
    End Property
    Public ReadOnly Property CoefficientB As Double
        Get
            Return Me.EndPoint.X - Me.StartPoint.X
        End Get
    End Property
    Public ReadOnly Property CoefficientC As Double
        Get
            Return Me.StartPoint.X * Me.EndPoint.Y - Me.EndPoint.X * Me.StartPoint.Y
        End Get
    End Property

    Public ReadOnly Property EquationOfLine As String
        Get
            Return $"({CoefficientA})x+({CoefficientB})y+({CoefficientC})=0"
        End Get
    End Property

    Public ReadOnly Property BoundingBox As ClsRectangle
        Get
            Dim rec As New ClsRectangle
            rec.GravityCenter = Me.Center
            rec.AngleToXails = 0
            rec.Height = Me.Delta.Y
            rec.Width = Me.Delta.X
            Return rec
        End Get
    End Property

    Public ReadOnly Property Center As ClsPoint2d
        Get
            Return Me.StartPoint.GetMidPointTo(Me.EndPoint)
        End Get
    End Property

#End Region

#Region "构造函数"
    Public Sub Createby2Pts(sp As ClsPoint2d, ep As ClsPoint2d)
        Me.StartPoint = sp
        Me.EndPoint = ep
    End Sub

    Public Sub CreatebySPAngleAndLength(sp As ClsPoint2d, angletoAxils As Double, length As Double)
        Me.StartPoint = sp
        Dim v As New ClsVector2d
        v.CreatorUnitVictor2dByAngle(angletoAxils)
        Me.EndPoint = Me.StartPoint.Add(v.Multiply(length))
    End Sub
#End Region

#Region "与cad转化"

    Public Function CreateFromAcadObject(obj As Object) As Boolean
        If TypeName(obj) <> "IAcadLine" Then
            Return False
        ElseIf Math.Abs(obj.StartPoint(2) - obj.EndPoint(2)) < 0.00000001 Then
            Dim sp As New ClsPoint2d, ep As New ClsPoint2d
            sp.CreatorByArray(obj.StartPoint)
            ep.CreatorByArray(obj.EndPoint)
            Me.StartPoint = sp
            Me.EndPoint = ep
            Return True
        Else
            Return False
        End If
    End Function

    Public Function ToAcadEntity(acLayout As Object) As Object
        Return acLayout.AddLine(Me.StartPoint.To3DArray(), Me.EndPoint.To3DArray())
    End Function
#End Region

#Region "直线与直线的位置关系"
    ''' <summary>
    ''' 直线与直线的位置关系
    ''' </summary>
    ''' <param name="line"></param>
    ''' <returns></returns>
    Public Function IsParallelTo(line As ClsLine2d) As Boolean
        Return Me.Delta.IsParallelTo(line.Delta)
    End Function


#End Region

#Region "直线与其他平面图元的关系"

    Public Function RelationToCircle(cir As ClsCircle) As 直线与圆的位置关系
        Dim dis = cir.Center.GetDistanceToLine(Me.StartPoint, Me.EndPoint)
        If dis > cir.Radius Then
            Return 直线与圆的位置关系.相离
        ElseIf dis = cir.Radius Then
            Return 直线与圆的位置关系.相切
        Else
            Return 直线与圆的位置关系.相交
        End If
    End Function


#End Region

#Region "求相交的点"
    ''' <summary>
    ''' 直线与直线的交点
    ''' </summary>
    ''' <param name="line"></param>
    ''' <returns></returns>
    Public Function GetCrossPointToLine(line As ClsLine2d) As ClsPoint2d
        If Me.IsParallelTo(line) Then
            Return Nothing
        Else
            Dim D = Me.CoefficientA * line.CoefficientB - Me.CoefficientB * line.CoefficientA
            Return New ClsPoint2d With {
                .X = (Me.CoefficientB * line.CoefficientC - Me.CoefficientC * line.CoefficientB) / D,
                .Y = (Me.CoefficientC * line.CoefficientA - Me.CoefficientA * line.CoefficientC) / D
            }
        End If
    End Function

    ''' <summary>
    ''' 直线与圆的交点
    ''' </summary>
    ''' <param name="cir"></param>
    ''' <returns></returns>
    Public Function GetCrossPointToCircle(cir As ClsCircle) As ClsPoint2d()
        Dim rtn As New List(Of ClsPoint2d)
        Select Case Me.RelationToCircle(cir)
            Case 直线与圆的位置关系.相交
                Dim vline = Me.Delta.DivideBy(Me.Length)
                Dim vspce = Me.StartPoint.GetVector2dTo(cir.Center)
                Dim p = Me.StartPoint.Add(vspce.ProjectionOnVector(vline))
                Dim dis = cir.Center.GetDistanceToLine(Me.StartPoint, Me.EndPoint)
                Dim 半弦长 = Math.Sqrt(cir.Radius * cir.Radius - dis * dis)
                rtn.AddRange({p.Add(vline.Multiply(半弦长)), p.Subtract(vline.Multiply(半弦长))})
            Case 直线与圆的位置关系.相切
                Dim vspce = Me.StartPoint.GetVector2dTo(cir.Center)
                Dim vspep = Me.StartPoint.GetVector2dTo(Me.EndPoint)
                Dim v = vspce.ProjectionOnVector(vspep)
                rtn.Add(Me.StartPoint.Add(v))
        End Select
        Return rtn.ToArray()
    End Function


#End Region

    Public Overrides Function ToString() As String
        Return Me.EquationOfLine
    End Function

#Region "Clone"
    Public Function Clone() As ClsLine2d

        Dim t As Type = Me.GetType()
        Dim setProps As List(Of PropertyInfo) = t.GetProperties.Where(Function(p) p.CanWrite).ToList()
        Dim rtnObj = Activator.CreateInstance(t)
        For Each p As PropertyInfo In setProps
            p.SetValue(rtnObj, p.GetValue(Me, Nothing), Nothing)
        Next
        Return DirectCast(rtnObj, ClsLine2d)

    End Function

#End Region

#Region "几何线性变换"
    ''' <summary>
    ''' 旋转当前直线
    ''' </summary>
    ''' <param name="angle">旋转角度,弧度制</param>
    ''' <param name="origin">旋转中心</param>
    Public Sub RotateTo(angle As Double, origin As ClsPoint2d)
        Me.StartPoint.Rotate(angle, origin)
        Me.EndPoint.Rotate(angle, origin)
    End Sub

    ''' <summary>
    ''' 旋转生成新的直线
    ''' </summary>
    ''' <param name="angle">旋转角度,弧度制</param>
    ''' <param name="origin">旋转中心</param>
    Public Function Rotate(angle As Double, origin As ClsPoint2d) As ClsLine2d

        Return New ClsLine2d With
            {
                 .StartPoint = Me.StartPoint.Rotate(angle, origin),
                .EndPoint = Me.EndPoint.Rotate(angle, origin)
            }

    End Function
    ''' <summary>
    ''' 缩放当前直线获取新的直线 
    ''' </summary>
    ''' <param name="scaleFactor">缩放的系数，大于1表示放大，小于1表示缩小</param>
    ''' <param name="scaleCenter">缩放的基准点</param>
    ''' <returns>新的直线 </returns>
    Public Function Scaling(ByVal scaleFactor As Double, ByVal scaleCenter As ClsPoint2d) As ClsLine2d
        Dim rtn As New ClsLine2d With {
            .StartPoint = Me.StartPoint.Scaling(scaleFactor, scaleCenter),
            .EndPoint = Me.EndPoint.Scaling(scaleFactor, scaleCenter)
            }

        Return rtn
    End Function

    ''' <summary>
    ''' 镜像当前直线获取新的直线 
    ''' </summary>
    ''' <param name="mirrorP1">对称轴第1点</param>
    ''' <param name="mirrorP2">对称轴第2点</param>
    ''' <returns>按照对称轴对称后的直线</returns>
    Public Function Mirror(ByVal mirrorP1 As ClsPoint2d, ByVal mirrorP2 As ClsPoint2d) As ClsLine2d
        Dim rtn As New ClsLine2d With {
            .StartPoint = Me.StartPoint.Mirror(mirrorP1, mirrorP2),
            .EndPoint = Me.EndPoint.Mirror(mirrorP1, mirrorP2)
            }
        Return rtn
    End Function

    ''' <summary>
    ''' 移动当前直线
    ''' </summary>
    ''' <param name="Displacement">移动目标点到初始点的向量</param>
    Public Sub MoveTo(Displacement As ClsVector2d)
        Me.StartPoint.X += Displacement.X
        Me.StartPoint.Y += Displacement.Y
        Me.EndPoint.X += Displacement.Y
        Me.EndPoint.Y += Displacement.Y
    End Sub
#End Region


End Class


